<?php

if (!defined('IN_APF'))
{
    die('Hacking attempt');
}

function exception_handler($e)
{
    print $e->format_stack_trace('<br />');
    exit(0);
}

function getLong($string, $type = 'V')
{
    $data = unpack($type, $string);

    return $data[1];
}

function getShort($string, $type = 'v')
{
    $data = unpack($type, $string);

    return $data[1];
}

function bigval($i, $scale = 0)
{
    return bcadd($i, 0, $scale);
}

function put_file($file, $content, $flag = 0)
{
    $pathinfo = pathinfo($file);

    if (!empty($pathinfo['dirname']))
    {
        if (file_exists($pathinfo['dirname']) === false)
        {
            if (@mkdir($pathinfo['dirname'], 0777, true) === false)
            {
                return false;
            }
        }
    }

    if ($flag === FILE_APPEND)
    {
        return @file_put_contents($file, $content, LOCK_EX | FILE_APPEND);
    }
    else
    {
        return @file_put_contents($file, $content, LOCK_EX);
    }
}

/* fopen / fread / fclose 读取部分内容的函数 */
function get_file_by_parts($file, $length, $offset = 0)
{
    $fp = @fopen($file, 'rb');
    if ($fp === false)
    {
        return false;
    }
    if ($offset > 0)
    {
        @fseek($fp, $offset);
    }
    $file_data = @fread($fp, $length);
    @fclose($fp);

    return $file_data;
}

/**
 * 递归得到目录下所有文件列表
 * @param string $path     当前路径
 * @param array  $allowExtensions    允许的扩展名
 * @param array  $unallowedExtensions  不允许的扩展名
 */
function scandir_recursive($path, $allowExtensions = array(), $unallowedExtensions = array(".", ".."))
{
    $result = array();
    if ($handle = opendir($path))
    {
        while (($item = readdir($handle)) !== false)
        {
            if (in_array($item, $unallowedExtensions))
            {
                continue;
            }
            if (is_dir($path . '/' . $item))
            {
                $result = array_merge($result, scandir_recursive($path . '/' . $item, $allowExtensions, $unallowedExtensions));
            }
            else
            {
                if ($allowExtensions)
                {
                    if (($pos = strrpos($item, ".")) !== false)
                    {
                        if (in_array(substr($item, $pos+1), $allowExtensions))
                        {
                            $result[] = $path . '/' . $item;
                        }
                    }
                }
                else
                {
                    $result[] = $path . '/' . $item;
                }
            }
        }
    }

    return $result;
}

/* HTTP 1.1 304 Not Modified 函数 */
function header_304()
{
    APF_header('Content-Type:');
    APF_header($_SERVER['SERVER_PROTOCOL'] .' 304 Not Modified', true, 304);

    exit;
}

/* HTTP 1.1 404 NOT FOUND 函数 */
function header_404($content = '')
{
    APF_header('Cache-Control: no-cache');
    APF_header($_SERVER['SERVER_PROTOCOL'] .' 404 Not Found', true, 404);

    exit("<h1>404 - Not Found" . $content . "</h1>\r\n");
}

/* HTTP 1.1 503 NOT FOUND 函数 */
function header_503($content = '')
{
    APF_header('Cache-Control: no-cache');
    APF_header($_SERVER['SERVER_PROTOCOL'] .' 503 - Service Temporarily Unavailable', true, 503);

    if ($content)
    {
        echo $content;
    }
    else
    {
        echo "<h1>503 - Service Temporarily Unavailable</h1>\r\n";
    }

    exit;
}

/* 转向函数 */
function redirect($url, $permanently = false)
{
    if ($permanently === true)
    {
        APF_header('Location: ' . $url, true, 301);
    }
    else
    {
        APF_header('Location: ' . $url, true, 302);
    }

    exit;
}

function APF_header($string, $replace = true, $http_response_code = 0)
{
    $string = str_replace(array("\r", "\n"), array('', ''), $string);

    if (preg_match('/^\s*location:/is', $string))
    {
        if ($http_response_code === 301)
        {
            @header($_SERVER['SERVER_PROTOCOL'] . ' 301 Moved Permanently', true, 301);
        }
        @header($string . "\r\n", $replace);

        exit;
    }

    if (empty($http_response_code))
    {
        @header($string, $replace);
    }
    else
    {
        @header($string, $replace, $http_response_code);
    }
}

function expires_header($source_time, $expire_time, $allow_304_header = false)
{
    APF_header('Cache-Control: max-age=' . $expire_time, true);

    /* 累加操作，避免因为 source_time+expire_time 小于当前时间，导致不能缓存 */
    while ($source_time + $expire_time <= REQUEST_TIME)
    {
        $expire_time += $expire_time;
    }

    APF_header('Expires: ' . http_date($source_time + $expire_time));

    $last_modified = http_date($source_time);
    if ($allow_304_header === true && isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) === true && strpos($_SERVER['HTTP_IF_MODIFIED_SINCE'], $last_modified) === 0)
    {
        header_304();

        exit;
    }

    APF_header('Last-Modified: ' . $last_modified);
}

/* 输出 ETag */
function output_etag($string, $allow_304_header = false)
{
    $etag = 'APF-' . abs(crc32($string));

    if ($allow_304_header === true && isset($_SERVER['HTTP_IF_NONE_MATCH']) === true && $etag === $_SERVER['HTTP_IF_NONE_MATCH'])
    {
        header_304();

        exit;
    }

    APF_header('ETag: ' . $etag);
}

/* htmlspecialchars 递归版本 */
function htmlspecialchars_deep($value)
{
    if (is_array($value) === true)
    {
        if (preg_match('/(\\\\\')+|["&]+/s', var_export($value, true)) === 1)
        {
            array_walk_recursive($value, 'callback_htmlspecialchars_deep');
        }
        return $value;
    }
    else
    {
        return htmlspecialchars($value, ENT_QUOTES);
    }
}

/* 被 array_walk_recursive 调用的函数，必须是两个参数 */
function callback_htmlspecialchars_deep(&$value, $key)
{
    $value = htmlspecialchars($value, ENT_QUOTES);
}

function is_leep_year($year = '')
{
    if (empty($year))
    {
        $year = date('Y');
    }

    if ($year % 4 === 0)
    {
        if ($year % 100 === 0)
        {
            return ($year % 400 === 0);
        }
        else
        {
            return true;
        }
    }
    else
    {
        return false;
    }
}

function get_days_by_month($year, $month)
{
    $year   = intval($year);
    $month  = intval($month);

    if ($month === 2)
    {
        if (is_leep_year($year))
        {
            return 29;
        }
        else
        {
            return 28;
        }
    }

    $days = array(
        1   => 31,
        3   => 31,
        4   => 30,
        5   => 31,
        6   => 30,
        7   => 31,
        8   => 31,
        9   => 30,
        10  => 31,
        11  => 30,
        12  => 31
    );

    return $days[$month];
}

/**
 * 指定时间距现在的时间描述
 *
 * @param int $time
 * @param int $length 从左往右数的长度
 * @param array $str_fix:array() 前缀或后缀
 *      ~ array(
 *          'prefix' => '过去',
 *          'suffix' => '前'
 *        )
 * @param array $lang_units
 * @return string
 */
function time_elapsed($time, $length = 6, $str_fix = array(), $lang_units = array())
{
    /* 避免时间差为零的情况 */
    $diff = REQUEST_TIME - $time + 1;

    if ($diff >= 259200)
    {
        return local_date('Y年m月d日', $time);
    }

    if ($str_fix === array())
    {
        $str_fix = array(
                'prefix' => '剩余',
                'suffix' => '前'
            );
    }

    if ($lang_units === array())
    {
        $lang_units = array(
                31536000 => '年',
                2592000  => '月',
                86400    => '天',
                3600     => '小时',
                60       => '分钟',
                1        => '秒',
            );
    }

    if ($diff < 0)
    {
        $prefix = $str_fix['prefix'] . ' ';
        $suffix = '';
    }
    else
    {
        $prefix = '';
        $suffix = ' ' . $str_fix['suffix'];
    }

    $result = '';
    $count  = 0; /* 已统计部分数量 */
    $diff   = abs($diff);
    foreach ($lang_units AS $k => $v)
    {
        if ($count >= $length)
        {
            break;
        }

        $num = floor($diff / $k);

        if ($num >= 1)
        {
            $result .= "$num{$v} ";
            $diff   -= $num * $k;
            ++$count;
        }
    }

    return $prefix . trim($result, ' ') . $suffix;
}

function relative_time($timestamp)
{
    $timestamp = intval($timestamp);
    $now = time();
    $delta = $now - $timestamp;

    if ($delta <= 60)
    {
        return '刚刚';
    }
    else if ($delta < 120)
    {
        return '一分钟前';
    }
    else if ($delta < 3600)
    {
        return intval($delta / 60) . '分钟前';
    }
    else if ($delta < 24 * 3600)
    {
        return intval($delta / 3600) . '小时前';
    }
    else if ($delta < 48 * 3600)
    {
        return '一天前';
    }
    else if ($delta < 96 * 3600)
    {
        return '几天前';
    }
    else
    {
        return date('Y-m-d H:i', $timestamp);
    }
}

function loadtime()
{
    if (defined('MICROTIME') === true)
    {
        return number_format(microtime(true) - MICROTIME, 4);
    }
    else
    {
        return 0.0000;
    }
}

function pagestatus($detail = false)
{
    start_performance();

    if ($detail === false)
    {
        $count_mysql     = $GLOBALS['_PERFORMANCE']->count_mysql();
        $count_memcached = $GLOBALS['_PERFORMANCE']->count_memcached();

        $string = '内存占用：' . loadmemory() . 'MB，';
        if ($count_mysql > 0)
        {
            $string .= 'DB 执行：' . $count_mysql . '次，';
        }
        if ($count_memcached !== 0)
        {
            $string .= 'MC 执行：' . $count_memcached . '次，';
        }

        if (!RUN_ENV || DEBUG_STATUS === true)
        {
            echo '<p>页面执行时间：' . loadtime() . '秒，' . $string . '</p>';
        }
        else
        {
            echo '<p>页面执行时间：' . loadtime() . '秒</p><!--COMPRESSRESERVED--><!--' . $string . '--><!--/COMPRESSRESERVED-->';
        }
    }
    else
    {
        if (!RUN_ENV || DEBUG_STATUS === true)
        {
            if (isset($GLOBALS['_PERFORMANCE']->DETAIL) === true)
            {
                $string = "<!--\r\n";
                foreach ($GLOBALS['_PERFORMANCE']->DETAIL AS $key => $value)
                {
                    $string .= "<-$key->{\r\n" . $value . "\r\n}\r\n";
                }

                echo "\r\n<!--COMPRESSRESERVED-->" . str_replace('-->', '--&gt;', $string) . "--><!--/COMPRESSRESERVED-->\r\n";
            }
        }
    }
}

function memory_use()
{
    return sprintf(' %0.3f MB', memory_get_usage(true) / 1048576);
}

function memory_max_use()
{
    return sprintf(' %0.3f MB', memory_get_peak_usage(true) / 1048576);
}

function staticize_url($url)
{
    if (SERVER_GROUP >= 3 || useNginx())
    {
        if (($pos = strpos($url, '.php?')) !== false)
        {
            if (isset($url{$pos + 5}) === true)
            {
                $url = str_replace(array('.php?', '&amp;', '=', '&'), array('-', '-', '-', '-'), $url) . '.html';
            }
            else
            {
                /*
                TODO: all .php => .html
                $url = strtr($url, '.php?', '.html');
                */
            }
        }
    }

    return $url;
}

function is_email($email)
{
    if (filter_var($email, FILTER_VALIDATE_EMAIL) === false)
    {
        return false;
    }

    return true;
}

function is_url($url)
{
    if (filter_var($url, FILTER_VALIDATE_URL) === false)
    {
        return false;
    }

    return true;
}

function is_ip($ip)
{
    if (filter_var($ip, FILTER_VALIDATE_IP) === false)
    {
        return false;
    }

    return true;
}

// 格式 年,月,日 如is_date('2000-1-2'),is_date('2000/1/2', '/')
function is_date($date, $split = '-')
{
    $date = str_replace(' ', '', $date);
    $dates = explode($split, $date);
    if (count($dates) != 3)
    {
        return false;
    }
    list($year, $month, $day) = $dates;
    $year = intval($year);
    $month = intval($month);
    $day = intval($day);
    if ($year < 10)
    {
        $year += 2000;
    }
    elseif ($year < 100)
    {
        $year += 1900;
    }

    return checkdate($month, $day, $year);
}

// 清理目录下过期文件
function clean_directory_by_time($dirname, $time = 86400)
{
    $dir = @opendir($dirname);
    if ($dir === false)
    {
        return 0;
    }

    $count = 0;
    while (($filename = @readdir($dir)) !== false)
    {
        if ($filename === '.' || $filename === '..')
        {
            continue;
        }
        if (@filemtime($dirname . $filename) < REQUEST_TIME - $time)
        {
            @unlink($dirname . $filename);
            ++$count;
        }
    }
    closedir($dir);

    return $count;
}

/* 对目录进行清理工作，可删除其中的文件，可一次传入多个目录，要求必须是绝对路径 */
function rm_rf($dirs)
{
    if (is_array($dirs) === false)
    {
        $dirs = (array)$dirs;
    }

    if ($dirs === array())
    {
        return true;
    }

    foreach ($dirs AS $dir)
    {
        if (empty($dir) === true || $dir{0} !== '/')
        {
            continue;
        }

        $dir = rtrim($dir, '/');

        $dh = @opendir($dir);
        if ($dh === false)
        {
            return false;
        }

        while (($file = @readdir($dh)) !== false)
        {
            if ($file === '.' || $file === '..')
            {
                continue;
            }
            @unlink($dir . '/' . $file);
        }
        closedir($dh);

        @rmdir($dir);
    }

    return true;
}

function dump_script_exec_profiler()
{
    $loadtime = loadtime();

    if ($loadtime >= 0.200)
    {
        $string   = $loadtime . '@' . date('H:i:s', REQUEST_TIME) . '|' . DOMAIN . '|' . DISPATCH_FILE . '|' . "\r\n\r\n";

        $log_file = LOG_PATH . '/exec_profiler_log/' . date('Ymd', REQUEST_TIME) . '.log';

        return put_file($log_file, $string, FILE_APPEND);
    }
    else
    {
        return true;
    }
}

/* 通过 app_name 获得 app_id */
function get_app_id($app_name, $project = PROJECT)
{
    if (isset($GLOBALS['APP_ID_CONFIGS']) === false)
    {
        require_once ROOT_PATH . '/' . $project . '/' . '/project_config/appid.system.php';
    }

    $app_name = str_replace('CLS_', '', $app_name);

    $key = array_search($app_name, $GLOBALS['APP_ID_CONFIGS']);
    if ($key !== false)
    {
        return $key;
    }
    else
    {
        trigger_error('[LIB_COMMON] get_app_id 函数获取地址出错，app_name=' . $app_name . var_export(debug_backtrace(), TRUE), E_USER_ERROR);

        return 0;
    }
}

/* 通过 app_id 获得 app_name */
function get_app_name($app_id, $error_report = false)
{
    if (isset($GLOBALS['APP_ID_CONFIGS']) === false)
    {
        require_once PROJECT_PATH . '/project_config/appid.system.php';
    }

    if (!empty($GLOBALS['APP_ID_CONFIGS'][$app_id]))
    {
        return strtolower($GLOBALS['APP_ID_CONFIGS'][$app_id]);
    }
    else
    {
        return '';
    }
}

/* 通过 app_id / app_name 获得 app 的描述 */
function get_app_desc($app_id)
{
    if (isset($GLOBALS['APP_ID_CONFIGS']) === false)
    {
        require_once PROJECT_PATH . '/project_config/appid.system.php';
    }

    /* 兼容支持 app_name */
    if (is_numeric($app_id) === false)
    {
        $app_name = $app_id;
        $app_id   = array_search($app_name, $GLOBALS['APP_ID_CONFIGS']);

        return empty($GLOBALS['APP_DESC_CONFIGS'][$app_id]) ? $app_name : $GLOBALS['APP_DESC_CONFIGS'][$app_id];
    }

    if (!empty($GLOBALS['APP_DESC_CONFIGS'][$app_id]))
    {
        return $GLOBALS['APP_DESC_CONFIGS'][$app_id];
    }
    else
    {
        trigger_error('[LIB_COMMON] get_app_desc 函数获取地址出错，app_id=' . $app_id, E_USER_ERROR);

        return '';
    }
}

function get_all_app_desc()
{
    if (isset($GLOBALS['APP_ID_CONFIGS']) === false)
    {
        require_once PROJECT_PATH . '/project_config/appid.system.php';
    }

    return $GLOBALS['APP_DESC_CONFIGS'];
}

/* 通过 app_id / app_name 获得 app 的描述 */
function get_app_path($app_id, $error_report = true, $project = PROJECT)
{
    if (isset($GLOBALS['APP_ID_CONFIGS']) === false)
    {
        require_once ROOT_PATH . '/' . $project . '/project_config/appid.system.php';
    }

    /* 兼容支持 app_name */
    if (is_numeric($app_id) === false)
    {
        $app_name = $app_id;
        $app_id = array_search($app_name, $GLOBALS['APP_ID_CONFIGS']);

        if (!empty($GLOBALS['APP_PATH_CONFIGS'][$app_id]))
        {
            return ROOT_PATH . $GLOBALS['APP_PATH_CONFIGS'][$app_id];
        }
        else
        {
            if ($error_report === true)
            {
                trigger_error('[LIB_COMMON] get_app_path 函数获取地址出错，app_name=' . $app_name, E_USER_ERROR);
            }

            return '';
        }
    }
    else
    {
        if (!empty($GLOBALS['APP_PATH_CONFIGS'][$app_id]))
        {
            return ROOT_PATH . $GLOBALS['APP_PATH_CONFIGS'][$app_id];
        }
        else
        {
            if ($error_report === true)
            {
                trigger_error('[LIB_COMMON] get_app_path 函数获取地址出错，app_id=' . $app_id, E_USER_ERROR);
            }

            return '';
        }
    }
}

function load_librarys_config()
{
    require_once FRAMEWORK_PATH . '/framework_config/library.system.php';
    if (defined('PROJECT') === false)
    {
        $GLOBALS['LIBRARY_CONFIGS'] = $GLOBALS['FRAMEWORK_LIBRARY_CONFIGS'];
    }
    else
    {
        require_once PROJECT_PATH   . '/project_config/library.system.php';

        $GLOBALS['LIBRARY_CONFIGS'] = array_merge($GLOBALS['FRAMEWORK_LIBRARY_CONFIGS'], $GLOBALS['PROJECT_LIBRARY_CONFIGS']);
    }
}

/* 通过 mod_name 获得 mod_id */
function get_mod_id($mod_name)
{
    if (isset($GLOBALS['MOD_ID_CONFIGS']) === false)
    {
        load_modules_config();
    }

    $mod_name = str_replace('cls_', '', $mod_name);

    $key = array_search($mod_name, $GLOBALS['MOD_ID_CONFIGS']);

    if ($key !== false)
    {
        return $key;
    }
    else
    {
        trigger_error('[LIB_COMMON] get_mod_id 函数获取地址出错，mod_name=' . $mod_name, E_USER_ERROR);

        return 0;
    }
}

function load_modules_config()
{
    require_once FRAMEWORK_PATH . '/framework_config/modid.system.php';
    require_once PROJECT_PATH   . '/project_config/modid.system.php';

    $GLOBALS['MOD_ID_CONFIGS']   = $GLOBALS['FRAMEWORK_MOD_ID_CONFIGS'];
    $GLOBALS['MOD_DESC_CONFIGS'] = $GLOBALS['FRAMEWORK_MOD_DESC_CONFIGS'];
    $GLOBALS['MOD_PATH_CONFIGS'] = $GLOBALS['FRAMEWORK_MOD_PATH_CONFIGS'];

    foreach ($GLOBALS['PROJECT_MOD_ID_CONFIGS'] AS $key => $value)
    {
        if (isset($GLOBALS['MOD_ID_CONFIGS'][$key]) === true)
        {
            exit('duplicate key in MOD_ID_CONFIGS');
        }
        $GLOBALS['MOD_ID_CONFIGS'][$key]   = $GLOBALS['PROJECT_MOD_ID_CONFIGS'][$key];
        $GLOBALS['MOD_DESC_CONFIGS'][$key] = $GLOBALS['PROJECT_MOD_DESC_CONFIGS'][$key];
        $GLOBALS['MOD_PATH_CONFIGS'][$key] = $GLOBALS['PROJECT_MOD_PATH_CONFIGS'][$key];
    }
}

function load_library_config()
{
    require_once FRAMEWORK_PATH . '/framework_config/library.system.php';
    if (defined('PROJECT') === false)
    {
        $GLOBALS['LIBRARY_CONFIGS'] = $GLOBALS['FRAMEWORK_LIBRARY_CONFIGS'];
    }
    else
    {
        require_once PROJECT_PATH   . '/project_config/library.system.php';

        $GLOBALS['LIBRARY_CONFIGS'] = array_merge($GLOBALS['FRAMEWORK_LIBRARY_CONFIGS'], $GLOBALS['PROJECT_LIBRARY_CONFIGS']);
    }
}

/* 通过 mod_id 获得 mod_name */
function get_mod_name($mod_id, $error_report = false)
{
    if (isset($GLOBALS['MOD_ID_CONFIGS']) === false)
    {
        load_modules_config();
    }

    if (!empty($GLOBALS['MOD_ID_CONFIGS'][$mod_id]))
    {
        return strtolower($GLOBALS['MOD_ID_CONFIGS'][$mod_id]);
    }
    else
    {
        return '';
    }
}

/* 通过 mod_id / mod_name 获得 mod 的描述 */
function get_mod_desc($mod_id)
{
    if (isset($GLOBALS['MOD_ID_CONFIGS']) === false)
    {
        load_modules_config();
    }

    /* 兼容支持 mod_name */
    if (is_numeric($mod_id) === false)
    {
        $mod_name = $mod_id;
        $mod_id   = array_search($mod_name, $GLOBALS['MOD_ID_CONFIGS']);

        return empty($GLOBALS['MOD_DESC_CONFIGS'][$mod_id]) ? $mod_name : $GLOBALS['MOD_DESC_CONFIGS'][$mod_id];
    }

    if (!empty($GLOBALS['MOD_DESC_CONFIGS'][$mod_id]))
    {
        return $GLOBALS['MOD_DESC_CONFIGS'][$mod_id];
    }
    else
    {
        trigger_error('[LIB_COMMON] get_mod_desc 函数获取地址出错，mod_id=' . $mod_id, E_USER_ERROR);

        return '';
    }
}

// 返回所有模块名称
function get_all_mod_name()
{
    if (isset($GLOBALS['MOD_ID_CONFIGS']) === false)
    {
        load_modules_config();
    }

    foreach ($GLOBALS['MOD_ID_CONFIGS'] AS &$v)
    {
        $v = strtolower($v);
    }

    return $GLOBALS['MOD_ID_CONFIGS'];
}

// 返回所有模块描述，一般添加时用到。用来输出选择模块的下拉列表
function get_all_mod_desc()
{
    if (isset($GLOBALS['MOD_ID_CONFIGS']) === false)
    {
        load_modules_config();
    }

    return $GLOBALS['MOD_DESC_CONFIGS'];
}

/* 通过 mod_id / mod_name 获得 mod 的描述 */
function get_mod_path($mod_id, $error_report = true)
{
    if (isset($GLOBALS['MOD_ID_CONFIGS']) === false || isset($GLOBALS['MOD_PATH_CONFIGS']) === false)
    {
        load_modules_config();
    }

    /* 兼容支持 mod_name */
    if (is_numeric($mod_id) === false)
    {
        $mod_name = $mod_id;
        $mod_id = array_search($mod_name, $GLOBALS['MOD_ID_CONFIGS']);

        if (!empty($GLOBALS['MOD_PATH_CONFIGS'][$mod_id]))
        {
            return ROOT_PATH . $GLOBALS['MOD_PATH_CONFIGS'][$mod_id];
        }
        else
        {
            if ($error_report === true)
            {
                trigger_error('[LIB_COMMON] get_mod_path 函数获取地址出错，mod_name=' . $mod_name, E_USER_ERROR);
            }

            return '';
        }
    }
    else
    {
        if (!empty($GLOBALS['MOD_PATH_CONFIGS'][$mod_id]))
        {
            return ROOT_PATH . $GLOBALS['MOD_PATH_CONFIGS'][$mod_id];
        }
        else
        {
            if ($error_report === true)
            {
                trigger_error('[LIB_COMMON] get_mod_path 函数获取地址出错，mod_id=' . $mod_id, E_USER_ERROR);
            }

            return '';
        }
    }
}

// 显示错误信息页面
function msg($msg, $jumpurl = '', $refresh_time = 10000)
{
    try {
        if (file_exists(ROOT_PATH . '/' . PROJECT . '/' . APP . '/theme/' . 'msg_web' . $GLOBALS['PROJECT_CONFIG']['template_postfix']))
        {
            $msgTPL = ROOT_PATH . '/' . PROJECT . '/' . APP . '/theme/' . 'msg_web' . $GLOBALS['PROJECT_CONFIG']['template_postfix'];
        }
        elseif (file_exists(ROOT_PATH . '/' . PROJECT . '/project_theme/common/' . 'msg_web' . $GLOBALS['PROJECT_CONFIG']['template_postfix']))
        {
            $msgTPL = ROOT_PATH . '/' . PROJECT . '/project_theme/common/' . 'msg_web' . $GLOBALS['PROJECT_CONFIG']['template_postfix'];
        }
        else
        {
            die('can not find exception template file.');
        }
        
        if (is_string($msg))
        {
            $tpl->assign('msg', $msg);  // $lang->get($msg)
        }
        elseif (is_array($msg) === true)
        {
            $all_msg = array();
            foreach ($msg AS $single_msg)
            {
                $all_msg[] = $lang->get($single_msg);
            }
            $tpl->assign('msg', $all_msg);
        }
        elseif (is_object($msg) === true)
        {
            if ($msg instanceof APF_Exception)
            {
                $tpl->assign('msg', '<pre>'.$msg->format_stack_trace('<br />').'</pre>');
            }
            else
            {
                $tpl->assign('msg', $msg);
            }
        }

        $tpl->display();
    }
    catch (Exception $e)
    {
        echo $e->getMessage();
    }

    exit(0);
}

/**
 * 计算字符串的长度（汉字按照两个字符计算）
 *
 * @param   string      $str        字符串
 *
 * @return  int
 */
function str_len($str)
{
    $length = strlen(preg_replace('/[\x00-\x7F]/', '', $str));

    if ($length)
    {
        return strlen($str) - $length + intval($length / 3) * 2;
    }
    else
    {
        return strlen($str);
    }
}

/**
 * 截取 UTF-8 编码下字符串的函数
 *
 * @param   string      $str              被截取的字符串
 * @param   int         $length           截取的长度
 * @param   bool        $append           是否附加省略号
 * @param   bool        $htmlspecialchars 是否进行转义操作
 *
 * @return  string
 */
function sub_str($str, $length = 0, $append = true, $htmlspecialchars = true)
{
    if ($length === 0 || isset($str{$length}) === false)
    {
        if ($htmlspecialchars === true)
        {
            return htmlspecialchars($str, ENT_QUOTES);
        }
        else
        {
            return $str;
        }
    }

    $str       = trim($str);
    $strlength = strlen($str);

    if ($length < 0)
    {
        $length = $strlength + $length;
        if ($length < 0)
        {
            $length = $strlength;
        }
    }

    $newstr = mb_substr($str, 0, $length, 'UTF-8');

    if ($append === true && $str !== $newstr)
    {
        $newstr .= '...';
    }

    if ($htmlspecialchars === true)
    {
        return htmlspecialchars($newstr, ENT_QUOTES);
    }
    else
    {
        return $newstr;
    }
}

/** 按字节截取字符串，半个汉字情况会自动适应 */
function truncate_str($str, $length = 50, $append = true, $htmlspecialchars = true)
{
    $s = '';
    if (strlen($str) > $length)
    {
        $s = mb_strcut($str, 0, $length, 'UTF-8');
        if ($append)
        {
            $s .= '...';
        }
    }
    else
    {
        $s = $str;
    }

    if ($htmlspecialchars)
    {
        $s = htmlspecialchars($s, ENT_QUOTES);
    }

    return $s;
}

function sub_str_by_screen($str, $length, $append = true, $htmlspecialchars = true)
{
    if ($length === 0 || isset($str{$length}) === false)
    {
        if ($htmlspecialchars === true)
        {
            return htmlspecialchars($str, ENT_QUOTES);
        }
        else
        {
            return $str;
        }
    }

    $i = 0;$j = 0;
    $strLength = strlen($str);
    while ($i < $strLength)
    {
        if ($str{$i} >= "\x80")
        {
            if ($j + 2 > $length)
            {
                break;
            }
            else
            {
                $i += 3;
                $j += 2;
            }
        }
        elseif ($j >= $length)
        {
            break;
        }
        else
        {
            ++$i;
            ++$j;
        }
    }

    if ($i === 0)
    {
        /* 处理字符串第一位字符是中文且 length = 1 的情况 */
        $newstr = mb_substr($str, 0, 1, 'UTF-8');
    }
    else
    {
        $newstr = substr($str, 0, $i);
    }

    if ($append && $str != $newstr)
    {
        $newstr .= '...';
    }

    if ($htmlspecialchars === true)
    {
        return htmlspecialchars($newstr, ENT_QUOTES);
    }
    else
    {
        return $newstr;
    }
}

function make_semiangle($str)
{
    static $arr = array(
                 '０' => '0', '１' => '1', '２' => '2', '３' => '3', '４' => '4',
                 '５' => '5', '６' => '6', '７' => '7', '８' => '8', '９' => '9',
                 'Ａ' => 'A', 'Ｂ' => 'B', 'Ｃ' => 'C', 'Ｄ' => 'D', 'Ｅ' => 'E',
                 'Ｆ' => 'F', 'Ｇ' => 'G', 'Ｈ' => 'H', 'Ｉ' => 'I', 'Ｊ' => 'J',
                 'Ｋ' => 'K', 'Ｌ' => 'L', 'Ｍ' => 'M', 'Ｎ' => 'N', 'Ｏ' => 'O',
                 'Ｐ' => 'P', 'Ｑ' => 'Q', 'Ｒ' => 'R', 'Ｓ' => 'S', 'Ｔ' => 'T',
                 'Ｕ' => 'U', 'Ｖ' => 'V', 'Ｗ' => 'W', 'Ｘ' => 'X', 'Ｙ' => 'Y',
                 'Ｚ' => 'Z', 'ａ' => 'a', 'ｂ' => 'b', 'ｃ' => 'c', 'ｄ' => 'd',
                 'ｅ' => 'e', 'ｆ' => 'f', 'ｇ' => 'g', 'ｈ' => 'h', 'ｉ' => 'i',
                 'ｊ' => 'j', 'ｋ' => 'k', 'ｌ' => 'l', 'ｍ' => 'm', 'ｎ' => 'n',
                 'ｏ' => 'o', 'ｐ' => 'p', 'ｑ' => 'q', 'ｒ' => 'r', 'ｓ' => 's',
                 'ｔ' => 't', 'ｕ' => 'u', 'ｖ' => 'v', 'ｗ' => 'w', 'ｘ' => 'x',
                 'ｙ' => 'y', 'ｚ' => 'z',
                 '（' => '(', '）' => ')', '〔' => '[', '〕' => ']', '【' => '[',
                 '】' => ']', '〖' => '[', '〗' => ']', '“' => '[', '”' => ']',
                 '‘' => '[', '’' => ']', '｛' => '{', '｝' => '}', '《' => '<',
                 '》' => '>',
                 '％' => '%', '＋' => '+', '—' => '-', '－' => '-', '～' => '-',
                 '：' => ':', '。' => '.', '、' => ',', '，' => '.', '、' => '.',
                 '；' => ',', '？' => '?', '！' => '!', '…' => '-', '‖' => '|',
                 '”' => '"', '’' => '`', '‘' => '`', '｜' => '|', '〃' => '"',
                 '　' => ' ', '＠' => '@');

    return strtr($str, $arr);
}

function output_js($js)
{
    $content = @file_get_contents($js);
    if ($content === false)
    {
        header_404(', errcode: OUTPUT_JS1');

        return false;
    }

    APF_header('Content-Type: application/x-javascript; charset=utf-8');

    /* 输出文件大小 */
    APF_header('Content-Length: ' . strlen($content));

    /* header 输出 */
    expires_header(filemtime($js), 3600 * 24 * 365);

    /* ETAG 输出 */
    output_etag($content);

    /* 输出文件内容 */
    echo $content;
}

function output_attachment($content, $filename, $content_type = '', $no_cache = false)
{
    /* MSIE 需要进行一下编码处理 */
    if (stripos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false)
    {
        APF_header('Content-Disposition: attachment; filename="' . urlencode($filename) . '"');
    }
    else
    {
        APF_header('Content-Disposition: attachment; filename="' . $filename . '"');
    }

    if ($content_type === '')
    {
        require_library('framework.fileinfo');
        $content_type = cls_fileinfo::get_mime_by_filename($filename);
        if ($content_type === false)
        {
            $content_type = 'application/octet-stream';
        }
    }
    APF_header('Content-Type: ' . $content_type);

    /* 不允许客户端缓存 */
    if ($no_cache === true)
    {
        APF_header('Cache-Control: no-store');
    }
    else
    {
        /* 输出文件大小 */
        APF_header('Content-Length: ' . strlen($content));

        /* ETAG 输出 */
        output_etag($content);
    }

    echo $content;
}

function array_spec_key($array, $key, $unset_key = false)
{
    if (empty($array) || !is_array($array))
    {
        return array();
    }

    $new_array = array();
    foreach ($array AS $value)
    {
        if (!isset($value[$key]))
        {
            continue;
        }
        $value_key = $value[$key];
        if ($unset_key === true)
        {
            unset($value[$key]);
        }
        $new_array[$value_key] = $value;
    }

    return $new_array;
}

function start_sessions()
{
    if (isset($GLOBALS['_SESSION']) === false)
    {
        require_module('framework.session');

        $GLOBALS['_SESSION'] = new Session(SITEID);
    }

    return $GLOBALS['_SESSION'];
}

/* 自定义的 LOGS 函数，目录先按年月组织，再在文件名后附加天。 */
function APF_log($file, $message)
{
    if (!$file)
    {
        return true;
    }

    if (is_array($message) === true)
    {
        $message = var_export($message, true);
    }

    put_file(LOG_PATH . '/' . date('Ym') . '/' . $file, $message . "\r\n", FILE_APPEND);    // . '-' . date('d')
}

function get_method_params($class, $method)
{
    if (empty($class) || empty($method))
    {
        return false;
    }

    require_module($class);

    list($project, $class) = explode('.', $class);
    $class = 'cls_' . $class;

    static $params = array();
    if (isset($params[$class . '::' . $method]))
    {
        return $params[$class . '::' . $method];
    }

    if (method_exists($class, $method) === false)
    {
        return false;
    }

    $reflect = new ReflectionMethod($class, $method);

    $my_params = array();
    foreach ($reflect->getParameters() AS $param)
    {
        $my_params[] = $param->getName();
    }

    $params[$class . '::' . $method] = $my_params;

    return $my_params;
}

function array_trim($array, $value = NULL)
{
    if ($array === array() || $array === NULL)
    {
        return array();
    }

    $new_array = array();
    foreach ($array AS $k => $v)
    {
        if (!trim($v, " \t\r\n\0\x0B$value"))
        {
            continue;
        }
        $new_array[$k] = $v;
    }

    return $new_array;
}

function cached_file_get_contents($filename, $cache_time = 15)
{
    return file_get_contents($filename);
/*
    $file_content = xc_get('filecache', $filename);
    if ($file_content === false)
    {
        $file_content = file_get_contents($filename);

        if ($file_content !== false)
        {
            xc_set('filecache', $filename, $file_content, $cache_time);
        }
    }

    return $file_content;
*/
}

function cached_parse_xml_file($filename, $cache_time = 15)
{
    $result = xc_get('xml_file_cache', $filename);
    if ($result === false)
    {
        $result = parse_xml(file_get_contents($filename));
        if (is_array($result) === true)
        {
            xc_add('xml_file_cache', $filename, $result, $cache_time);
        }
    }

    return $result;
}

function cached_parse_ini_file($filename, $cache_time = 15)
{
    return parse_ini_file($filename, true);
/*
    $ini_array = apc_fetch('ini_' . $filename);
    if ($ini_array === false)
    {
        $ini_array = parse_ini_file($filename, true);

        if (is_array($ini_array) === true)
        {
            apc_add('ini_' . $filename, $ini_array, $cache_time);
        }
    }

    return $ini_array;
*/
}

/**
 * dom2array XML转换成数组 post by hs.
 * @param string $xmlString     xml content
 */
function dom2array($xmlString)
{
    static $domDoc;

    if (!$domDoc)
    {
        $domDoc = new DOMDocument();
    }
    $domDoc->preserveWhiteSpace=false;
    if (!@$domDoc->loadXML($xmlString))
    {
        return false;
    }

    return _dom2array($domDoc);
}

function _dom2array($node)
{
    $result = array();
//static $i = 0;echo "<p>第 $i 次进来,节点名：{$node->nodeName} ({$node->nodeType}) 节点值：{$node->nodeValue} "; $i++;
    if ($node->nodeType == XML_TEXT_NODE)
    {
        //echo "<h3>{$node->nodeValue}</h3>";
        return $node->nodeValue;
    }
    if ($node->hasAttributes())
    {
        $result['@attributes'] = array();
        foreach ($node->attributes AS $attr)
        {
            $result['@attributes'][strtolower($attr->name)] = $attr->value;
        }
    }
    if ($node->hasChildNodes())
    {
        foreach ($node->childNodes AS $nodeChild)
        {
            if ($node->firstChild->nodeName == $node->lastChild->nodeName&&$node->childNodes->length > 1)
            {
                $result[strtolower($nodeChild->nodeName)][] = _dom2array($nodeChild);
            }
            else
            {
                $result[strtolower($nodeChild->nodeName)][] = _dom2array($nodeChild);
            }
        }
    }

    return $result;
}

function require_framework_file($file)
{
    static $required = array();

    if (isset($required[$file]) === true)
    {
        return true;
    }
    else
    {
        $required[$file] = true;
    }

    return require_once FRAMEWORK_PATH . $file;
}

function require_module_config($mod, $file = '')
{
    static $required = array();

    if (isset($required[$mod . $file]) === true)
    {
        return true;
    }
    else
    {
        $required[$mod . $file] = true;
    }

    if ($mod === 'framework.domain')
    {
        return require_once FRAMEWORK_PATH . "/module/domain/domain.config.php";
    }

    if (defined('PROJECT_PATH') === true)
    {
        $project_name = PROJECT;
        $project_path = PROJECT_PATH;
    }
    else
    {
        $project_name = Framework::$current_project;
        $project_path = ROOT_PATH . Framework::$current_project;
    }

    list($project, $name) = explode('.', $mod);

    if ($file === '')
    {
        if ($project === 'framework')
        {
            return require_once $project_path . "/project_config/framework_module_config/$mod.config.php";
        }
        elseif ($project === $project_name)
        {
            return require_once get_mod_path($mod) . "/$name.config.php";
        }
        else
        {
            return require_once $project_path . "/project_config/external_module_config/$mod.config.php";
        }
    }
    else
    {
        /* 临时兼容，以后还要去掉 */
        if ($project === 'framework')
        {
            return require_once $project_path . "/project_config/framework_module_config" . $file;
        }
        else
        {
            exit('die in require_module_config...');
        }
    }
}

function require_app_config($appName, $fn = '')
{
    return require_once get_app_path($appName) . '/config/' . ($fn ? $fn : "$appName.domain.php");
}

function require_module_file($mod, $file)
{
    static $required = array();

    if (isset($required[$mod . $file]) === true)
    {
        return true;
    }
    else
    {
        $required[$mod . $file] = true;
    }

    return require_once get_mod_path($mod) . $file;
}

function require_module($mod)
{
    static $required = array();

    if (isset($required[$mod]) === true)
    {
        return true;
    }
    else
    {
        $required[$mod] = true;
    }

    list($project, $name) = explode('.', $mod);

    return require_once get_mod_path($mod) . "/$name.class.php";
}

function require_module_helper($mod)
{
    static $helpered = array();

    if (isset($helpered[$mod]) === true)
    {
        return true;
    }
    else
    {
        $helpered[$mod] = true;
    }

    list($project, $name) = explode('.', $mod);

    return require_once get_mod_path($mod) . "/$name.helper.php";
}

function require_library($lib)
{
    static $required = array();

    if (isset($required[$lib]) === true)
    {
        return true;
    }
    else
    {
        $required[$lib] = true;
    }

    if (isset($GLOBALS['LIBRARY_CONFIGS'][$lib]) === true)
    {
        return require_once ROOT_PATH . $GLOBALS['LIBRARY_CONFIGS'][$lib];
    }
    else
    {
        load_librarys_config();
        if (isset($GLOBALS['LIBRARY_CONFIGS'][$lib]) === true)
        {
            return require_once ROOT_PATH . $GLOBALS['LIBRARY_CONFIGS'][$lib];
        }
        else
        {
//          throw new cls_exception("require_library {$lib} failed!");
            trigger_error("require_library {$lib} failed!", E_USER_ERROR);
        }
    }
}

function require_librarys()
{
    $libs = func_get_args();

    static $required = array();

    foreach ($libs AS $lib)
    {
        if (isset($required[$lib]) === true)
        {
            continue;
        }
        else
        {
            $required[$lib] = true;
        }

        if (isset($GLOBALS['LIBRARY_CONFIGS'][$lib]) === true)
        {
            require_once ROOT_PATH . $GLOBALS['LIBRARY_CONFIGS'][$lib];
        }
        else
        {
            load_librarys_config();
            if (isset($GLOBALS['LIBRARY_CONFIGS'][$lib]) === true)
            {
                require_once ROOT_PATH . $GLOBALS['LIBRARY_CONFIGS'][$lib];
            }
        }
    }

    return true;
}

// build app menu
function build_app_menu()
{
    $lang = Framework::$lang;

    if (!isset($GLOBALS['TAB_LIST'][$lang]))
    {
        require_app_config(APP);
    }
    // 根据文件名找出对应的tabs
    $scriptFileName = $GLOBALS['REQUEST_INFO']['url'];

    if (isset($GLOBALS['TAB_LIST'][$scriptFileName]))
    {
        $tabs = $GLOBALS['TAB_LIST'][$scriptFileName][$lang];
    }
    else
    {
        $tabs = $GLOBALS['TAB_LIST']['default'][$lang];
    }

    // 得到当前的附action的文件名$currentURL
    if ($GLOBALS['TAB_LIST']['cur_tab'] != "self")
    {
        $currentURL = $GLOBALS['TAB_LIST']['cur_tab'];
    }
    else
    {
        $currentURL = $GLOBALS['REQUEST_INFO']['url'];
        if ($GLOBALS['REQUEST_INFO']['query_string'])
        {
            $tmp = explode('&', $GLOBALS['REQUEST_INFO']['query_string']);
            foreach ($tmp AS $v)
            {
                $tmp2 = explode('=', $v);
                if (count($tmp2) == 2 && $tmp2[0] == 'a' && $tmp2[1] != 'show')
                {
                    $currentURL .= "?$v";
                }
            }
        }
    }

    $html = '<ul>';
    foreach ($tabs AS $lnk => $title)
    {
        if (substr($lnk, 0, 7) === 'http://' || substr($lnk, 0, 8) === 'https://')
        {
            $html .= '<li><a target="blank" href="'.$lnk.'">'.$title.'</a></li>';
            continue;
        }

        if ($currentURL == $lnk)
        {
            $tmpURL = staticize_url($GLOBALS['TAB_LIST']['disp_cur_link'] ? get_domain_name_by_app(APP, true).'/'.$lnk : "#");
            $html .= '<li><a href="'.$tmpURL.'" class="current">'.$title.'</a></li>';
        }
        else
        {
            $tmpURL = staticize_url(get_domain_name_by_app(APP, true).'/'.$lnk);
            $html .= '<li><a href="'.$tmpURL.'">'.$title.'</a></li>';
        }
    }
    $html .= '</ul>';

    return $html;
}

function append_app_menu($title, $position = 'END', $disp_cur_link = true)
{
    $lang = Framework::$lang;

    if (!isset($GLOBALS['TAB_LIST'][$lang]))
    {
        require_app_config(APP);
    }

    $scriptFileName = $GLOBALS['REQUEST_INFO']['url'];
    $lnk = $scriptFileName.($GLOBALS['REQUEST_INFO']['query_string'] ? "?". $GLOBALS['REQUEST_INFO']['query_string'] : "");
    set_current_tab($lnk);
    if (isset($GLOBALS['TAB_LIST'][$scriptFileName]))
    {
        if ($position != 'END' && $position >= 0 && $position < count($GLOBALS['TAB_LIST'][$scriptFileName][$lang]))
        {
            $GLOBALS['TAB_LIST'][$scriptFileName][$lang] = array_merge(
                array_slice($GLOBALS['TAB_LIST'][$scriptFileName][$lang], 0, $position, true),
                array($lnk => $title),
                array_slice($GLOBALS['TAB_LIST'][$scriptFileName][$lang], $position, count($GLOBALS['TAB_LIST'][$scriptFileName][$lang]), true)
            );
        }
        else
        {
            $GLOBALS['TAB_LIST'][$scriptFileName][$lang][$lnk] = $title;
        }
    }
    else
    {
        if ($position != 'END' && $position >= 0 && $position < count($GLOBALS['TAB_LIST']['default'][$lang]))
        {
            $GLOBALS['TAB_LIST']['default'][$lang] = array_merge(
                array_slice($GLOBALS['TAB_LIST']['default'][$lang], 0, $position, true),
                array($lnk => $title),
                array_slice($GLOBALS['TAB_LIST']['default'][$lang], $position, count($GLOBALS['TAB_LIST']['default'][$lang]), true)
            );
        }
        else
        {
            $GLOBALS['TAB_LIST']['default'][$lang][$lnk] = $title;
        }
    }
    $GLOBALS['TAB_LIST']['disp_cur_link'] = $disp_cur_link;

    return true;
}

function set_current_tab($lnk, $disp_cur_link = true)
{
    if (!isset($GLOBALS['TAB_LIST'][Framework::$lang]))
    {
        require_app_config(APP);
    }
    $GLOBALS['TAB_LIST']['cur_tab'] = $lnk;
    $GLOBALS['TAB_LIST']['disp_cur_link'] = $disp_cur_link;

    return true;
}

function start_performance()
{
    if (isset($GLOBALS['_PERFORMANCE']) === false)
    {
        require_library('framework.performance');

        $GLOBALS['_PERFORMANCE'] = new cls_performance();
    }

    return $GLOBALS['_PERFORMANCE'];
}

function url_encode($url)
{
    return strtr(base64_encode($url), '+-/=', '|()^');
}

function url_decode($encode_url)
{
    return base64_decode(strtr($encode_url, '|()^', '+-/='));
}

/**
 * Call FirePHP
 *
 * @return mixed
 */
function fb()
{
    require_library('framework.firephp');

    $instance = FirePHP::getInstance(true);

    $args = func_get_args();

    return call_user_func_array(array($instance, 'fb'), $args);
}

/**
 * 检查数组是否有效
 *
 * @param Array $data 要检查的数组
 * @param Array $keys_to_check 数组中需要检查的keys
 * @param Boolean $strict 数组是否应该只含有指定的键(可选, 默认为False)
 * @throws cls_exception 如果进行检查的数组不合法, 抛'invalid_args'异常
 * @return void void
 * @author Kinch Zhang(a.k.a daqing) <kinch.zhang@gmail.com>
 */
function check_array($data, $keys_to_check, $strict=False)
{
    if (!isset($data))
    {
        throw new cls_exception('data_is_not_set');
    }

    /**
     * 检查$data的键是否和指定的数组完全相同
     *
     * NOTE: 由于array_diff只能判断foo是否为bar的子集, 所以需要用两次才能判断foo和bar是否相等
     */
    if ($strict)
    {
        $keys = array_keys($data);
        if ($keys !== $keys_to_check)
        if (array_diff($keys, $keys_to_check) || array_diff($keys_to_check, $keys))
        {
            throw new cls_exception('data_keys_not_match:' . var_dump($data));
        }
    }

    /** 检查$data数组中至少含有$keys_to_check中指定的key, 并且key对应的value不能为empty */
    foreach ($keys_to_check AS $k)
    {
        if (!array_key_exists($k, $data) || !isset($data[$k]))
        {
            throw new cls_exception('data_key_[' . $k . ']_not_exist_or_empty');
        }
    }
}

function get_domain_name_by_app($app, $http = false, $main_domain = MAIN_DOMAIN)
{
    if ($app === 'www')
    {
        return $http === true ? 'http://www.' . $main_domain : 'www.' . $domain_name;
    }

    /* 对 watermark 进行特殊处理，在具体使用的情况下用 esqimg.com 返回 */
    if ($app === 'watermark' && @constant('SERVER_GROUP') > 2 && @constant('APP') !== 'admin')
    {
        $domain_name = $app .  '.' . MAIN_DOMAIN;

        return $http === true ? 'http://' . $domain_name : $domain_name;
    }

    /* 静态变量，优化速度 */
    static $domain_name_array = NULL;

    if (empty($domain_name_array[$main_domain][$app]))
    {
        require_module('framework.domain');
        $domain_name = Domain::get_domain_name_by_app($app, $main_domain);
        if (empty($domain_name))
        {
            if ($app === 'dstatic' || $app === 'js' || $app === 'theme' || $app === 'thumb' || $app === 'watermark' || $app === 'kingjs')
            {
                if (SERVER_GROUP === 1)
                {
                    $domain_name = get_all_domain_name_by_app($app, 'dahai1.com');
                }
                elseif (SERVER_GROUP === 2)
                {
                    $domain_name = get_all_domain_name_by_app($app, 'dahai1.cn');
                }
                elseif (SERVER_GROUP === 3)
                {
                    $domain_name = get_all_domain_name_by_app($app, 'esqimg.com');
                }
                else
                {
                    if ($app === 'theme' || $app === 'kingjs')
                    {
                        $domain_name = get_all_domain_name_by_app($app, 'esqimg.com');
                    }
                    else
                    {
                        $domain_name = get_all_domain_name_by_app($app, 'ygimg.com');
                    }
                }
            }
            elseif ($app === 'admin')
            {
                $domain_name = array('admin.eshequn.com');
            }
            else
            {
                $domain_name = array('www.eshequn.com');
            }
        }

        $domain_name_array[$main_domain][$app] = $domain_name;
    }
    else
    {
        $domain_name = $domain_name_array[$main_domain][$app];
    }

    if (isset($domain_name[0]))
    {
        $domain_name = $domain_name[array_rand($domain_name)];
    }

    return $http === true ? 'http://' . $domain_name : $domain_name;
}






















function dbserver_connect($server_settings, $postfix = NULL)
{
    if ($postfix === NULL)
    {
        $settings = $server_settings;
    }
    else
    {
        if (isset($postfix{2}) === true)
        {
            trigger_error('[dbserver_connect] dbserver 后缀非法: ' . $postfix, E_USER_ERROR);
        }
        if (isset($server_settings[$postfix]) === true)
        {
            $settings = $server_settings[$postfix];
        }
        /* 当精度高于 1 时，允许指定配置 1 位宽的服务器地址，即相当于 0*、a*、f* 这样的配置 */
        elseif (isset($postfix{1}) === true && isset($server_settings[$postfix{0}]) === true)
        {
            $settings = $server_settings[$postfix{0}];
        }
        else
        {
            $settings = $server_settings['default'];
        }
    }

    $db = &$GLOBALS['db'];
    if (is_object($db) == false)
    {
        require_library('framework.mysql');

        if (SERVER_GROUP == 1 || SERVER_GROUP == 2)
        {
            $db = new cls_mysql($settings, 'utf8');
        }
        else
        {
            $db = new cls_mysql($settings);
        }
    }
    elseif ($db->settings !== $settings)
    {
        $db->close();
        $db->parse_settings($settings);
    }

    return $db;
}

function get_mcserver_settings($hosts_alias)
{
    /* only for domain module */
    if (is_array($hosts_alias) === false)
    {
        return array($hosts_alias);
    }

    if (isset($GLOBALS['MEMCACHED_SERVER_CONFIGS']) === false)
    {
        require_once ROOT_PATH . '/' . PROJECT . '/project_config/memcached.system.php';
    }

    $servers = $GLOBALS['MEMCACHED_SERVER_CONFIGS'][$hosts_alias[0]];

    if (is_array($servers) === false)
    {
        $servers = array($servers . $hosts_alias[1]);
    }
    else
    {
        $old_servers = $servers;

        $servers = array();
        foreach ($old_servers AS $key => $value)
        {
            if ($key === 'precision')
            {
                $servers[precision] = $value;
            }
            else
            {
                $servers[$key] = $value . $hosts_alias[1];
            }
        }
    }

    return $servers;
}

function mcserver_connect($server_settings)
{
    $mc = &$GLOBALS['mc'];
    if (is_object($GLOBALS['mc']) === false)
    {
        require_library('framework.memcached');

        $mc = new cls_memcached($server_settings);
    }
    elseif ($mc->settings !== $server_settings)
    {
        $mc->parse_settings($server_settings);
    }

    return $mc;
}

function mcserver_set($hosts_alias, $key, $value, $expire = 60)
{
    if ($value === true || $value === false)
    {
        trigger_error('[mcserver_set] 不能存放布尔值', E_USER_ERROR);
    }

    $hosts = get_mcserver_settings($hosts_alias);
    if (isset($hosts['precision']) === true)
    {
        $hosts = $hosts[abs(crc32($key)) % $hosts['precision']];
    }

    foreach ($hosts AS $host)
    {
        mcserver_connect($host);
        $result = $GLOBALS['mc']->set($key, $value, $expire);
    }

    return $result;
}

function mcserver_sets($hosts_alias, $prefix, $data, $expire = 60)
{
    if ($data === array())
    {
        return false;
    }

    $hosts = get_mcserver_settings($hosts_alias);
    if (isset($hosts['precision']) === false)
    {
        mcserver_connect($hosts[0]);
    }
    else
    {
        mcserver_connect($hosts[0][0]);
    }

    if (empty($prefix))
    {
        $prefix = $GLOBALS['mc']->prefix;
    }
    else
    {
        $prefix = $GLOBALS['mc']->prefix . '_' . $prefix;
    }

    $new_data = array();
    foreach ($data AS $key => $value)
    {
        $new_data[$prefix . '_' . $key] = $value;
    }

    if (isset($hosts['precision']) === false)
    {
        $hosts_array[0] = $hosts;
        $data_array[0]  = $new_data;
    }
    elseif ($hosts['precision'] === 1)
    {
        $hosts_array[0] = $hosts[0];
        $data_array[0]  = $new_data;
    }
    else
    {
        $data_array = $hosts_array = array();
        foreach ($new_data AS $key => $value)
        {
            $mod = abs(crc32($key)) % $hosts['precision'];

            $hosts_array[$mod]      = $hosts[$mod];
            $data_array[$mod][$key] = $value;
        }
    }

    foreach ($hosts_array AS $key => $host)
    {
        foreach ($host AS $host_single)
        {
            mcserver_connect($host_single);
            $result = $GLOBALS['mc']->sets($data_array[$key], $expire);
        }
    }

    return $result;
}

function mcserver_delete($hosts_alias, $key)
{
    if (empty($key) === true)
    {
        return;
    }

    $hosts = get_mcserver_settings($hosts_alias);
    if (isset($hosts['precision']) === true)
    {
        $hosts = $hosts[abs(crc32($key)) % $hosts['precision']];
    }

    foreach ($hosts AS $host)
    {
        mcserver_connect($host);
        $result = $GLOBALS['mc']->delete($key);
    }

    return $result;
}

function mcserver_deletes($hosts_alias, $keys)
{
    if ($keys === array())
    {
        return;
    }

    $hosts = get_mcserver_settings($hosts_alias);
    if (isset($hosts['precision']) === false)
    {
        mcserver_connect($hosts[0]);
    }
    else
    {
        mcserver_connect($hosts[0][0]);
    }

    $new_keys = array();
    foreach ($keys AS $key)
    {
        $new_keys[] = $GLOBALS['mc']->prefix . '_' . $key;
    }

    if (isset($hosts['precision']) === false)
    {
        $hosts_array[0] = $hosts;
        $keys_array[0]  = $new_keys;
    }
    elseif ($hosts['precision'] === 1)
    {
        $hosts_array[0] = $hosts[0];
        $keys_array[0]  = $new_keys;
    }
    else
    {
        $hosts_array = array();
        $keys_array  = array();
        foreach ($new_keys AS $key)
        {
            $mod = abs(crc32($key)) % $hosts['precision'];

            $hosts_array[$mod]  = $hosts[$mod];
            $keys_array[$mod][] = $key;
        }
    }

    foreach ($hosts_array AS $key => $host)
    {
        foreach ($host AS $host_single)
        {
            mcserver_connect($host_single);
            $result = $GLOBALS['mc']->deletes($keys_array[$key]);
        }
    }

    return $result;
}

function mcserver_flushs($hosts_alias)
{
    $hosts = get_mcserver_settings($hosts_alias);
    if (is_array($hosts) === false)
    {
        $hosts = array($hosts);
    }
    else
    {
        if (isset($hosts['precision']) === true)
        {
            $hosts_tmp = array();
            foreach ($hosts AS $key => $host)
            {
                if ($key == 'precision')
                {
                    continue;
                }
                $hosts_tmp[] = $host;
            }
            $hosts = array_unique($hosts_tmp);
        }
    }

    foreach ($hosts AS $host)
    {
        mcserver_connect($host);
        $result = $GLOBALS['mc']->flush();
    }

    return $result;
}

function mcserver_get($hosts_alias, $key)
{
    $hosts = get_mcserver_settings($hosts_alias);
    if (isset($hosts['precision']) === true)
    {
        $hosts = $hosts[abs(crc32($key)) % $hosts['precision']];
    }

    if (isset($hosts[1]) === false)
    {
        mcserver_connect($hosts[0]);
    }
    else
    {
        mcserver_connect($hosts[rand(0, count($hosts) - 1)]);
    }

    return $GLOBALS['mc']->get($key);
}

function mcserver_gets($hosts_alias, $prefix, $keys, &$ungets = NULL)
{
    if ($keys === array())
    {
        return array();
    }

    $hosts = get_mcserver_settings($hosts_alias);
    if (isset($hosts['precision']) === false)
    {
        mcserver_connect($hosts[0]);
    }
    else
    {
        mcserver_connect($hosts[0][0]);
    }

    if (empty($prefix))
    {
        $prefix = $GLOBALS['mc']->prefix;
    }
    else
    {
        $prefix = $GLOBALS['mc']->prefix . '_' . $prefix;
    }

    // $cache_keys存放最终缓存keys(以原始key为索引), $prefix_keys存放用户传入缓存keys(以最终key为索引)
    $cache_keys = $prefix_keys = array();
    foreach ($keys AS $key)
    {
        $t = $prefix . '_' . $key;

        $cache_keys[$key] = $t;
        $prefix_keys[$t]  = $key;
    }

    // $mc_keys存放最终缓存keys(以原始key为索引)
    $mc_keys = $cache_keys;
    if (isset($hosts['precision']) == false)
    {
        $hosts_array[0] = $hosts;
        $keys_array[0]  = $mc_keys;
    }
    elseif ($hosts['precision'] == 1)
    {
        $hosts_array[0] = $hosts[0];
        $keys_array[0]  = $mc_keys;
    }
    else
    {
        $keys_array = $hosts_array = array();
        foreach ($mc_keys AS $key)
        {
            $mod = abs(crc32($key)) % $hosts['precision'];

            $hosts_array[$mod]  = $hosts[$mod];
            $keys_array[$mod][] = $key;
        }
    }

    $final_array = array();
    foreach ($hosts_array AS $key => $host)
    {
        mcserver_connect($host[rand(0, count($host) - 1)]);
        $result = $GLOBALS['mc']->gets($keys_array[$key]);
        if ($result !== false)
        {
            $final_array = array_merge($final_array, $result);
        }
    }

    $last_final_array = array();
    foreach ($final_array AS $key => $value)
    {
        $last_final_array[$prefix_keys[$key]] = $value;
    }

    if ($ungets !== NULL)
    {
        $ungets = array_diff($keys, array_keys($last_final_array));
    }

    return $last_final_array;
}

function mcserver_inc($host_alias, $key, $step = 1)
{
    if (empty($key) === true)
    {
        return false;
    }

    $host = get_mcserver_settings($host_alias);

    mcserver_connect($host);

    return $GLOBALS['mc']->inc($key, $step);
}

function exit_failed($array = array(), $fastcgi_finish_request = false)
{
    if (!is_array($array))
    {
        $array = (array)$array;
    }

    if ($array === array())
    {
        /* array('failed' => true) */
        $result = 'a:1:{s:6:"failed";b:1;}';
    }
    else
    {
        $array['failed'] = true;

        $result = serialize($array);
    }

    if ($fastcgi_finish_request === false)
    {
        exit($result);
    }
    else
    {
        echo $result;

        fastcgi_finish_request();
    }
}

function exit_array($array = array(), $fastcgi_finish_request = false)
{
    if ($array === array())
    {
        /* 空数组 */
        $result = 'a:0:{}';
    }
    else
    {
        $result = serialize($array);
    }

    if ($fastcgi_finish_request === false)
    {
        exit($result);
    }
    else
    {
        echo $result;

        fastcgi_finish_request();
    }
}

function gen_hash_token($string, $length = 1)
{
    if ($length < 1)
    {
        return  false;
    }

    if (is_numeric($string))
    {
        return substr(str_pad(strrev(dechex($string)), $length, '0'), 0, $length);
    }
    else
    {
        return substr(md5($string), 0, $length);
    }
}

function get_hash_tokens($precision = 1)
{
    $total_num = pow(16, $precision);

    $result = array();
    for ($i = 0; $i < $total_num; ++$i)
    {
        $result[] = gen_hash_token($i, $precision);
    }

    return $result;
}

/**
 * 对跨数据库的一些keys，进行分组。如果$span_length=1，则在最差的情况下会有16组。
 * $keep_order用于保持数组原有的键名顺序，而不是重新编号。
 *
 * @access public
 * @param array $token_keys
 * @param integer $span_length
 * @param boolean $keep:false
 * @return array|false
 */
function group_array_by_token_keys($token_keys, $span_length = 1, $keep_order = false)
{
    if (!is_array($token_keys) || $span_length < 1)
    {
        return false;
    }

    $grouped_token_keys = array();
    if ($keep_order)
    {
        foreach ($token_keys AS $idx => $token_key)
        {
            $token = gen_hash_token($token_key, $span_length);
            $grouped_token_keys[$token][$idx] = $token_key;
        }
    }
    else
    {
        foreach ($token_keys AS $token_key)
        {
            $token = gen_hash_token($token_key, $span_length);
            $grouped_token_keys[$token][] = $token_key;
        }
    }

    return $grouped_token_keys;
}

function db_create_in($item_list, $field_name = '')
{
    if (!is_array($item_list))
    {
        $item_list = explode(',', $item_list);
    }
    if (empty($item_list))
    {
        return $field_name . " IN ('') ";
    }
    $item_list = array_unique($item_list);

    return $field_name . " IN ('" . implode("','", $item_list) . "') ";
}

function get_referer_uri()
{
    $hash = fetch_post('apf_referer_uri', 'string', '');
    if ($hash === '')
    {
        $hash = fetch_get('apf_referer_uri', 'string', '');
    }
    if (empty($hash))
    {
        return '';
    }

    $referer_uris = get_referer_uris();

    foreach ($referer_uris AS $k => $referer_uri)
    {
        if ($referer_uri[0] === $hash)
        {
            unset($referer_uris[$k]);
            apf_setcookie('apf_referer_uris', json_encode($referer_uris), '', 1800);

            return $referer_uri[1];
        }
    }

    return '';
}

function get_referer_uris()
{
    $referer_uris = fetch_cookie('apf_referer_uris', 'string', '');
    if ($referer_uris === '')
    {
        return array();
    }

    $referer_uris = @json_decode(stripslashes($referer_uris), true);
    if (empty($referer_uris) || !is_array($referer_uris))
    {
        return array();
    }

    return $referer_uris;
}

function get_files_last_time($source_files, &$time_hash = NULL, &$miss_file = NULL)
{
    $source_files_time = 0;

    foreach ($source_files AS $file)
    {
        if ($file === '' || $file === '/')
        {
            continue;
        }

        if ($file{0} === '/')
        {
            $file = substr($file, 1);
        }

        $file_time = @filemtime(ROOT_PATH . '/' . $file);
        if ($file_time === false)
        {
            if ($miss_file !== NULL)
            {
                $miss_file = $file;
            }

            $source_files_time = false;

            break;
        }
        else
        {
            if ($file_time > $source_files_time)
            {
                $source_files_time = $file_time;
            }

            if ($time_hash !== NULL)
            {
                $time_hash .= (string)$file_time;
            }
        }
    }

    if ($source_files_time !== false && $time_hash !== NULL)
    {
        $time_hash = hash('crc32b', $time_hash);
    }

    return $source_files_time;
}

/**
 * 获得用户浏览器的信息
 *
 * @return array
 */
function getBrowser($ua = '')
{
    if ($ua === '')
    {
        $ua = $GLOBALS['REQUEST_INFO']['ua'];
    }

    if ($ua === '')
    {
        return array();
    }

    $prefix   = 'framework';
    $cacheKey = 'userBrowsers_' . md5($ua);
    $browser  = xc_get($prefix, $cacheKey);

    if (empty($browser) === true)
    {
        $browser = get_browser($ua, true);
        xc_add($prefix, $cacheKey, $browser, 86400);
    }

    return $browser;
}

/**
 *
 * @param $interval 单位为秒
 */
function floorTime($ts, $interval = 60)
{
    if ($ts > $interval && $interval > 1)
    {
        return $ts - $ts % $interval;
    }
    else
    {
        return $ts;
    }
}

function useNginx()
{
    return !isset($_SERVER['SERVER_SOFTWARE']) || substr($_SERVER['SERVER_SOFTWARE'], 0, 5) === 'nginx';
}

/**
 * 获得经典的数据库表配置
 *
 * 如: getClassicalTableConfig(eshequn.soft.db_soft)
 *
 * 返回结果:
 * array(
 *  'default'       => 'mysql://root:kodak.sq@192.168.0.201:3306/?soft'
 *  'table_name'    => 'apf_soft',
 *  'table_key'     => array('soft_id')
 * )
 *
 * @param $fullTableName
 * @return unknown_type
 */
function getClassicalTableConfig($fullTableName)
{
    require_once ROOT_PATH . '/framework/module/da/test/Environment.class.php';
    require_once ROOT_PATH . '/framework/module/da/test/ConfigUtils.class.php';

    $setting = xc_get('getClassicalTableConfig', $fullTableName);
    if ($setting !== false)
    {
        return $setting;
    }

    list($project, $mod, $table) = explode('.', $fullTableName);
    require_module_config($project . '.' . $mod);

    if (SERVER_GROUP < 3)
    {
        Environment::setProperty(Environment::CFG_PATH,  PROJECT_PATH . '/project_config/dal_config/dal-11.xml');
    }
    else
    {
        if (strlen($GLOBALS[$mod . '_module_settings']['dal'][$table]) > 6)
        {
            $cluster = substr($GLOBALS[$mod . '_module_settings']['dal'][$table], 7);
            Environment::setProperty(Environment::CFG_PATH,  PROJECT_PATH . '/project_config/dal_config/dal-' . $cluster. '.xml');
        }
        else
        {
            throw new cls_exception('invalid_args');
        }
    }

    Environment::setProperty(Environment::DATA_HOME,  '/dev/shm/da');

    $config = ConfigUtils::getTableConfig($fullTableName);

    $setting = array(
        'default'   => buildMySQLURL($config['mainTable']['dbUrlInfo']),
        'table_name'=> $config['mainTable']['logicalTableName'],
    );

    if (isset($config['mainTable']['precision']) && isset($config['mainTable']['scatterColumnName']))
    {
        $setting['precision']   = $config['mainTable']['precision'];
        $setting['token_key']   = $config['mainTable']['scatterColumnName'];
        $setting['table_key']   = getTablePrimaryKey($setting['default'], $setting['table_name'] . '_');
    }
    else
    {
        $setting['table_key']   = getTablePrimaryKey($setting['default'], $setting['table_name']);
    }

    if (isset($config['helpingTables']) && count($config['helpingTables']) > 0)
    {
        foreach ($config['helpingTables'] as $k => $v)
        {
            $mysqlURL = buildMySQLURL($v['dbUrlInfo']);
            $setting['relational'][$k] = array(
                'default'   => $mysqlURL,
            );

            if (isset($v['scatterColumnName']) && isset($v['precision']))
            {
                $setting['relational'][$k]['precision'] = $v['precision'];
                $setting['relational'][$k]['token_key'] = $v['scatterColumnName'];
                $setting['relational'][$k]['table_key'] = getTablePrimaryKey($mysqlURL, $k . '_');
            }
            else
            {
                $setting['relational'][$k]['table_key'] = getTablePrimaryKey($mysqlURL, $k);
            }
        }
    }

    xc_add('getClassicalTableConfig', $fullTableName, $setting, 60);

    return $setting;
}

function buildMySQLURL($urlInfo)
{
    return 'mysql://' . $urlInfo['username'] . ':' . $urlInfo['password']
        . '@' . $urlInfo['ip'] . ':' . $urlInfo['port'] . '/?' . $urlInfo['database'];
}

function getTablePrimaryKey($mysqlURL, $tableName)
{
    $db     = dbserver_connect($mysqlURL);
    $rows   = $db->getAll('DESC ' . $tableName);
    $keys   = array();
    foreach ($rows as $row)
    {
        if ($row['Key'] == 'PRI')
        {
            $keys[] = $row['Field'];
        }
    }

    return $keys;
}

function dump()
{
    static $count = 0;
    $argsNum = func_num_args();
    $args = func_get_args();
    if (extension_loaded('xdebug'))
    {
        echo "<pre><p><strong>**************BEGIN DEBUG($count)************** at ".xdebug_call_class()."::".xdebug_call_function()."() [".xdebug_call_file()." : <font color=red>".xdebug_call_line()."</font>]</strong></p>";
    }
    else
    {
        echo "<p>Debug info (no xdebug extension)</p>";
    }
    for ($i = 0; $i < $argsNum; ++$i)
    {
        if (is_array($args[$i]) && !empty($args[$i]))
        {
            print_r($args[$i]);
        }
        else
        {
            var_dump($args[$i]);
        }
    }
    echo "<p><strong>**************END DEBUG($count)**************</strong></p></pre>\n";

    $count++;
}

function logdump()
{
    static $count = 0;
    $argsNum = func_num_args();
    $args = func_get_args();
    $str = '';
    if (extension_loaded('xdebug'))
    {
        $str .= "**************BEGIN DEBUG($count)************** at ".xdebug_call_class()."::".xdebug_call_function()."() [".xdebug_call_file()." : <font color=red>".xdebug_call_line()."\n";
    }
    else
    {
        $str .= "Debug info (no xdebug extension)\n";
    }
    for ($i = 0; $i < $argsNum; ++$i)
    {
        $str .= var_export($args[$i], true)."\n";
    }

    $count++;
    $str .= "**************END DEBUG($count)**************\n";
    $log_file = LOG_PATH . '/logdump.log';

    return put_file($log_file, $str, FILE_APPEND);
}

?>
